﻿using System;
using System.Linq;
using System.IO;
using System.IO.IsolatedStorage;
using System.Collections.Generic;
using System.Windows.Controls;
using Microsoft.LightSwitch;
using Microsoft.LightSwitch.Framework.Client;
using Microsoft.LightSwitch.Presentation;
using Microsoft.LightSwitch.Presentation.Extensions;
using Microsoft.LightSwitch.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices.Automation;
using System.Dynamic;
using System.Collections.Specialized;

namespace LightSwitchApplication
{
    public partial class PRO_CodaProduzione
    {
        partial void PRO_CodaProduzione_Activated()
        {
            //var po = this.FindControl("ImageViewer");
            //po.ControlAvailable += new EventHandler<ControlAvailableEventArgs>(po_ControlAvailable);

            var po1 = this.FindControl("ImageViewer1");
            po1.ControlAvailable += new EventHandler<ControlAvailableEventArgs>(po1_ControlAvailable);

            var gridC = this.FindControl("grid");
            gridC.ControlAvailable += new EventHandler<ControlAvailableEventArgs>(gridC_ControlAvailable);
        }

        TelerikWrappedControl.CustomImageViewer imageViewer;
        void po1_ControlAvailable(object sender, ControlAvailableEventArgs e)
        {
            imageViewer = e.Control as TelerikWrappedControl.CustomImageViewer;
        }

        TelerikWrappedControl.CodaProduzioneTelerikGrid grid;
        void gridC_ControlAvailable(object sender, ControlAvailableEventArgs e)
        {
            grid = e.Control as TelerikWrappedControl.CodaProduzioneTelerikGrid;
        }

        //Image imageCtrl;
        //void po_ControlAvailable(object sender, ControlAvailableEventArgs e)
        //{
        //    imageCtrl = e.Control as Image;
        //    if (imageCtrl != null)
        //    {
        //        imageCtrl.Stretch = System.Windows.Media.Stretch.Uniform;

        //        imageCtrl.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(imageCtrl_MouseLeftButtonDown);
        //    }

        //}

        //void imageCtrl_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        //{
        //    //Dispatchers.Main.BeginInvoke(() =>
        //    //   {
        //    //       var filePath1 = GetCurrentImageFilePath();

        //    //       // if (!File.Exists(filePath1)) return;

        //    //       //var shell1 = AutomationFactory.CreateObject("WScript.Shell");
        //    //       //shell1.Run(filePath1);

        //    //       var shell1 = AutomationFactory.CreateObject("Shell.Application");

        //    //       shell1.ShellExecute(filePath1);

        //    //       //var shell = AutomationFactory.CreateObject(@"C:\Windows\System32\rundll32.exe");

        //    //       //shell.ShellExecute(@"C:\Windows\system32\shimgvw.dll,ImageView_Fullscreen " + filePath1);
        //    //   });


        //    Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() =>
        //    {
        //        var filePath1 = GetRelativeImagePath();

        //        if (AutomationFactory.IsAvailable)
        //        {
        //            dynamic shell = AutomationFactory.CreateObject("Shell.Application");

        //            shell.ShellExecute(filePath1);
        //        }
        //        else if (!System.Windows.Application.Current.IsRunningOutOfBrowser)
        //        {
        //            System.Windows.Browser.HtmlPage.Window.Navigate(new Uri(filePath1, UriKind.RelativeOrAbsolute), "_new");
        //        }
        //        else
        //        {
        //            throw new InvalidOperationException();
        //        }

        //    });

        //}

        //private string GetRelativeImagePath()
        //{
        //    var hostName = string.Empty;
        //    var port = 0;

        //    Dispatchers.Main.Invoke(() =>
        //    {
        //        hostName = System.Windows.Application.Current.Host.Source.DnsSafeHost;
        //        port = System.Windows.Application.Current.Host.Source.Port;
        //    });

        //    //// better to keep this in a global config singleton
        //    //string hostName = Application.Current.Host.Source.Host;
        //    if (hostName.ToLower() != "localhost")
        //        if (port != 80)
        //            hostName += ":" + port;

        //    return string.Format("http://{0}/Gestione11/Images/{1}", hostName, GetCurrentImageName());

        //}

        //private string GetCurrentImageName()
        //{
        //    return DettagliDocumento.SelectedItem.Articolo.CodiceArticolo + ".jpg";
        //}
        partial void DettagliDocumento_SelectionChanged()
        {
            if (imageViewer != null && DettagliDocumento.SelectedItem != null)
            {
                // data di consegna
                var d = DettagliDocumento.SelectedItem.DataConsegna.HasValue ? DettagliDocumento.SelectedItem.DataConsegna.Value.ToShortDateString() : string.Empty;

                // Carica Image Viewer
                imageViewer.TryLoadImage(DettagliDocumento.SelectedItem.Articolo.CodiceArticolo, 
                                         DettagliDocumento.SelectedItem.Documento.CodiceDocumentoEsterno, 
                                         DettagliDocumento.SelectedItem.Documento.Anagrafica.RagioneSociale,
                                         DettagliDocumento.SelectedItem.Quantità.ToString(), 
                                         d);
            }
        }

        #region Calcolo Disponibiltà Ore
        /// <summary>
        /// Crea record riepilogo ordine.
        /// Serve sapere il ritardo alla determinata data.
        /// </summary>
        partial void ShowOreImpegno_Execute()
        {
            // todo : fare riepilogo ore per ordine.
            if (!OrdineIdFilter.HasValue)
            { }

            // Cancello tutti i precendenti record.
            foreach (RiepilogoImpegnoOreDettaglio i in DataWorkspace.ApplicationData.RiepilogoImpegnoOre)
                i.Delete();

            Save();

            var artSO = new List<string>();

            // raggruppo i vari articoli da produrre in base alla data di consegna
            //  todo : aggiungere anche stato avanzamento.
            var groups = from g in DettagliDocumento.Where(d => d.Documento.TipoDocumento == (int)TipoDocumento.OrdineCliente && !d.Documento.Archiviato
                                                            && (d.StatoAvanzamento == (int)StatoAvanzamento.InCoda ||
                                                               d.StatoAvanzamento == (int)StatoAvanzamento.MaterialeDaTagliare ||
                                                               d.StatoAvanzamento == (int)StatoAvanzamento.MaterialeOrdinato ||
                                                               d.StatoAvanzamento == (int)StatoAvanzamento.TagliatoInCoda))
                         orderby g.DataConsegna
                         group g by g.DataConsegna
                             into ng
                             select ng;

            var orario = new OrarioDiLavoro();

            var now = DateTime.Now;

            // Itero per le varie lavorazioni creando vari record
            foreach (Lavorazione lavorazione in DataWorkspace.ApplicationData.Lavorazioni)
            {
                var totaleMinutiImpegno = 0.0m;

                //var totOrePrec = 0.0m;

                var datePrecedentiFlag = false;

                foreach (var d in groups)
                {
                    var dataC = d.Key;


                    // faccio sommatoria di tutte le date di consegna precedenti e null
                    if (dataC < now.Date || dataC == null || dataC.HasValue == false)
                    {
                        foreach (var l in d)
                        {
                            if (l.Articolo == null) continue;

                            if (l.Articolo.DettagliImpegnoOre.Count() == 0)
                            {
                                //Aggiungo alla lista di articoli senza ore settate .
                                if (!artSO.Contains(l.Articolo.CodiceArticolo))
                                    artSO.Add(l.Articolo.CodiceArticolo);
                                continue;
                            }

                            var dLav = l.Articolo.DettagliImpegnoOre.Where(l1 => l1.Lavorazione.Id == lavorazione.Id);

                            foreach (var p in dLav)
                            {
                                totaleMinutiImpegno += p.MinutiPerLotto + (p.MinutiPerPezzo * l.Quantità);
                            }
                        }

                        continue;
                    }

                    // se ci sono state consegne precedenti all'attuale
                    if (totaleMinutiImpegno > 0 && !datePrecedentiFlag)
                    {
                        var rec1 = DataWorkspace.ApplicationData.RiepilogoImpegnoOre.AddNew();

                        rec1.DataConsegna = now;
                        rec1.Lavorazione = lavorazione;
                        rec1.OreImpegno = totaleMinutiImpegno / 60;

                        var oreImpegno1 = rec1.OreImpegno;

                        var nDataConsegna = orario.GetDataFineLavori(now, Math.Abs(oreImpegno1));

                        rec1.DataConsegnaPrevista = nDataConsegna;
                        rec1.OreRitardo = Math.Abs(oreImpegno1);

                        datePrecedentiFlag = true;
                    }

                    var modFlag = false;

                    foreach (var l in d)
                    {
                        if (l.Articolo == null) continue;

                        if (l.Articolo.DettagliImpegnoOre.Count() == 0)
                        {
                            //Aggiungo alla lista di articoli senza ore settate .
                            if (!artSO.Contains(l.Articolo.CodiceArticolo))
                                artSO.Add(l.Articolo.CodiceArticolo);
                            continue;
                        }

                        if (!l.Articolo.DettagliImpegnoOre.Any(dd => dd.Lavorazione.Id == lavorazione.Id))
                            continue;

                        foreach (var p in l.Articolo.DettagliImpegnoOre)
                        {
                            if (p.Lavorazione.Id != lavorazione.Id) continue;

                            totaleMinutiImpegno += p.MinutiPerLotto + (p.MinutiPerPezzo * l.Quantità);
                            modFlag = true;
                        }
                    }

                    // todo : gestire consegne senza data.

                    if (!modFlag) continue;

                    if (!dataC.HasValue) continue;

                    // Creo record per ogni data di consegna con macchina , ore , e data consegna prevista.
                    var rec = DataWorkspace.ApplicationData.RiepilogoImpegnoOre.AddNew();

                    rec.DataConsegna = dataC.Value;
                    rec.Lavorazione = lavorazione;
                    rec.OreImpegno = totaleMinutiImpegno / 60;

                    var dataConsegna = dataC.Value;

                    var oreImpegno = rec.OreImpegno;

                    Console.WriteLine("Scadenza del {0} , ci sono {1} ore di lavoro complessive previste", dataConsegna.ToShortDateString(), oreImpegno);

                    var deltaOre = orario.GetOreDisponibili(now, dataConsegna);

                    // Il campo TotaleOre, serve solamente per chiarire meglio come viene effettuato il calcolo delle ore.
                    rec.TotaleOre = deltaOre > 0 ? deltaOre : 0;

                    var rimanenzaOre = deltaOre - oreImpegno;

                    if (rimanenzaOre > 0) // Disponibilità ore
                    {
                        var nDataConsegna = orario.GetDataFineLavori(now, oreImpegno);

                        rec.DataConsegnaPrevista = nDataConsegna;

                        rec.DisponibilitaOre = Math.Abs(rimanenzaOre);
                    }
                    else if (rimanenzaOre == 0)
                    {
                        //Console.WriteLine("La consegna del {0} è puntuale",
                        //                  dataConsegna.ToShortDateString());
                    }
                    else // Ritardo
                    {
                        //var nDataConsegna = orario.GetDataFineLavori(dataConsegna, Math.Abs(rimanenzaOre));

                        var nDataConsegna = orario.GetDataFineLavori(now, oreImpegno);

                        rec.DataConsegnaPrevista = nDataConsegna;

                        rec.OreRitardo = Math.Abs(rimanenzaOre);

                    }

                    Console.WriteLine();
                }
            }

            Save();

            this.Application.ShowRPG_ImpegnoOre(artSO.Count);
        }

        public class OrarioDiLavoro
        {
            public List<DayOfWeek> Festivi = new List<DayOfWeek> { DayOfWeek.Sunday, DayOfWeek.Saturday };

            public double OreLavGiornaliere = 8;

            public List<int> OrariLavoro = new List<int> { 8, 9, 10, 11, 14, 15, 16, 17 };


            public DateTime GetDataFineLavori(DateTime start, decimal totaleOreLavoro)
            {
                while (totaleOreLavoro > 0)
                {
                    if (!Festivi.Contains(start.DayOfWeek) && OrariLavoro.Contains(start.Hour))
                        totaleOreLavoro -= 1;

                    start = start.AddHours(1);
                }

                // 
                //if (OrariLavoro.Any(i => start.Hour > i))
                //{
                //    start = start.AddDays(1);
                //}

                return start;
            }

            /// <summary>
            /// Calcola il totale ore lavorative totali fra 2 date.
            /// </summary>
            /// <param name="start"></param>
            /// <param name="end"></param>
            /// <returns></returns>
            public decimal GetOreDisponibili(DateTime start, DateTime end)
            {
                var oreDisponibili = 0.0m;

                var inizio = start < end ? start : end;
                var fine = start < end ? end : start;
                var isDateBehind = start >= end;

                // L'ora della data finale deve avere orario settato tipo a 23:59. altrimenti non conta le ore di quel giorno.
                fine = fine.Subtract(new TimeSpan(fine.Hour, fine.Minute, fine.Second)).Add(new TimeSpan(23, 59, 00));

                while (inizio < fine)
                {
                    if (!Festivi.Contains(inizio.DayOfWeek) && OrariLavoro.Contains(inizio.Hour))
                    {
                        oreDisponibili += 1;
                    }

                    inizio = inizio.AddHours(1);
                }

                if (isDateBehind)
                    return -oreDisponibili;
                return oreDisponibili;

            }
        }

        #endregion
        /// <summary>
        /// Metodo per settare in modo automatico il tempo approsimativo di lavoro
        /// </summary>
        partial void CalcoloAutomatico_Execute()
        {
            var art = DettagliDocumento.SelectedItem.Articolo;

            var dett = DettagliDocumento.SelectedItem;

            var importoTotale = DettagliDocumento.SelectedItem.TotaleRiga;

            var costiTotali = Articolo.ImportoTotaleMateriale * dett.Quantità;

            var rimanente = importoTotale - costiTotali;

            var matPrimo = art.DettagliMaterialeArticolo.FirstOrDefault();

            // se il materiale non è settato non riesco a definire impegno automatico

            if (matPrimo == null) return;

            var lav = GetLavFromMat(matPrimo.MaterialeGrezzo);

            if (lav == null) return;

            var cOrario = lav.CostoOrario;

            var ore = rimanente / cOrario;

            if (ore < 0) return;

            var dettImpegno = art.DettagliImpegnoOre.AddNew();

            dettImpegno.Lavorazione = lav;

            dettImpegno.MinutiPerLotto = (int)(ore * 60);
        }

        /// <summary>
        /// Molto rude . prendo tornio con tondo e centro con piatto
        /// </summary>
        /// <param name="mat"></param>
        /// <returns></returns>
        /// 
        private Lavorazione GetLavFromMat(MaterialeGrezzo mat)
        {
            if (mat == null) return null;

            var sez = mat.Sezione;

            switch (sez)
            {
                case 0:
                case 1:
                case 5:
                case 6:
                    return DataWorkspace.ApplicationData.Lavorazioni.Where(l => l.Descrizione == "Tornio").FirstOrDefault();

                case 2:
                case 3:
                case 4:
                    return DataWorkspace.ApplicationData.Lavorazioni.Where(l => l.Descrizione == "Centro di Lavoro").FirstOrDefault();

                default:
                    return null;
            }
        }



        const string wndStato = "WndSetStato";
        partial void SetStatoAvanzamento_Execute()
        {
            this.Details.Dispatcher.BeginInvoke(() =>
                {
                    this.OpenModalWindow(wndStato);

                    this.FindControl(wndStato).ControlAvailable += new EventHandler<ControlAvailableEventArgs>(CodaProduzione_ControlAvailable);
                });
        }

        void CodaProduzione_ControlAvailable(object sender, ControlAvailableEventArgs e)
        {
            this.FindControl(wndStato).ControlAvailable -= new EventHandler<ControlAvailableEventArgs>(CodaProduzione_ControlAvailable);

            ((ChildWindow)e.Control).Closed += new EventHandler(DocumentiListDetail_Closed);
            ((ChildWindow)e.Control).Closing += new EventHandler<System.ComponentModel.CancelEventArgs>(PRO_CodaProduzione_Closing);
        }

        void PRO_CodaProduzione_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            ((ChildWindow)sender).Closing -= new EventHandler<System.ComponentModel.CancelEventArgs>(PRO_CodaProduzione_Closing);

            if (StatoAvanzametoDlg == null)
            {
                e.Cancel = true;
                return;
            }
            this.Details.Dispatcher.BeginInvoke(() =>
            {
                // cambia stato avanzamento
                if (grid == null) return;
                {
                    var l = grid.SelectedItems;

                    foreach (DettaglioDocumento dett in l)
                        dett.StatoAvanzamento = StatoAvanzametoDlg;
                }


                StatoAvanzametoDlg = null;

                Save();
            });
        }

        void DocumentiListDetail_Closed(object sender, EventArgs e)
        {
            ((ChildWindow)sender).Closed -= new EventHandler(DocumentiListDetail_Closed);

        }

        partial void InCodaCmd_Execute()
        {
            this.Details.Dispatcher.BeginInvoke(() =>
            {
                grid.InCoda();
            });
        }

        partial void PulisciFiltroCmd_Execute()
        {
            // SearchParameter = null;
            this.Details.Dispatcher.BeginInvoke(() =>
                {
                    grid.ClearFilter();
                });

        }

        partial void DettagliDocumento_Validate(ScreenValidationResultsBuilder results)
        {
            // results.AddPropertyError("<Error-Message>");

        }

        partial void MostraTempoTotale_Execute()
        {
            var selected = DettagliImpegnoOre.SelectedItem;

            if (selected == null) return;

            var l = DettagliImpegnoOre.SelectedItem.MinutiPerLotto + (DettagliImpegnoOre.SelectedItem.MinutiPerPezzo * DettagliDocumento.SelectedItem.Quantità);

            var time = TimeSpan.FromMinutes(l);

            this.ShowMessageBox(string.Format("Voce Selezionata : {2} : , Tempo Totale : {0} ore {1} minuti", Math.Round(time.TotalHours), time.Minutes, DettagliImpegnoOre.SelectedItem.Lavorazione.Descrizione));
        }
    }
}
